package com.generator.api.impl;

import com.generator.api.IDServiceApi;
import com.generator.config.ServiceConfig;
import com.generator.exception.IdGeneratorException;
import com.generator.persistence.EpochPersistence;
import com.generator.utils.NetUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.atomic.AtomicLong;

@Slf4j
@Service
@com.alibaba.dubbo.config.annotation.Service
public class IDServiceApiImpl implements IDServiceApi, InitializingBean {

    @Resource
    private ServiceConfig serviceConfig;

    @Resource
    private EpochPersistence epochPersistence;

    private static final long BASE = -1;

    private long maxEpoch;
    private int epochShiftBits;

    private long workerId;
    private int workerIdShiftBits;

    private long dataCenterId;
    private int dataCenterShiftBits;

    private long maxOffset;

    /**
     * 周期值
     */
    private final AtomicLong epoch = new AtomicLong(0);

    /**
     * 序列号
     */
    private final AtomicLong sequence = new AtomicLong(0);

    @Override
    public long nextId() {
        long currEpoch;

        long currSequence;

        do {

            currEpoch = epoch.get();

            currSequence = sequence.getAndIncrement();

            if(currSequence <= maxOffset) {
                break;
            }

            if(currEpoch >= maxEpoch) {
                throw new IdGeneratorException("所有序列号已用完");
            }

            synchronized (this) {

                boolean success = epochPersistence.upgradeEpoch(currEpoch+1);

                if(success) {
                    epoch.set(currEpoch+1);
                    sequence.set(0);
                }
            }

        } while (true);

        return currEpoch << epochShiftBits
                | dataCenterId << dataCenterShiftBits
                | workerId << workerIdShiftBits
                | currSequence;
    }

    @Override
    public void afterPropertiesSet() {

        long newEpoch = epochPersistence.loadEpoch();

        int epochBits = serviceConfig.getEpochBits();

        int workerBits = serviceConfig.getWorkerBits();
        this.workerId = serviceConfig.getWorkerId();

        int dataCenterBits = serviceConfig.getDataCenterBits();
        this.dataCenterId = serviceConfig.getDataCenterId();
        int offsetBits = 63 - epochBits - dataCenterBits - workerBits;

        workerIdShiftBits = offsetBits;
        dataCenterShiftBits = workerIdShiftBits + workerBits;
        epochShiftBits = dataCenterShiftBits + dataCenterBits;

        this.maxEpoch = ~(BASE << epochBits);

        this.maxOffset = ~(BASE << offsetBits);

        this.epoch.set(newEpoch);

        this.sequence.set(0);

        log.info("[IDServiceApi] 当前节点信息 >>> address:{}," +
                "dataCenterId:{},dataCenterBits:{}" +
                "workerId:{},workerIdBits:{}" +
                "初始epoch:{},epochBits:{}", NetUtils.getHostForIPV4(),dataCenterId,dataCenterBits,workerId,workerBits,epoch.get(),epochBits);
    }

}
